Skip to content

feat: [EPIC-GW-03] 本地控制面契约硬化 (JSON-RPC 2.0 切换)#302

Merged
phantom5099 merged 4 commits into
1024XEngineer:mainfrom
pionxe:feat/gateway-epic-gw-03-jsonrpc-hardening
Apr 15, 2026
Merged

feat: [EPIC-GW-03] 本地控制面契约硬化 (JSON-RPC 2.0 切换)#302
phantom5099 merged 4 commits into
1024XEngineer:mainfrom
pionxe:feat/gateway-epic-gw-03-jsonrpc-hardening

Conversation

@pionxe

@pionxe pionxe commented Apr 15, 2026

Copy link
Copy Markdown
Collaborator

🎯 目标 (Motivation & Context)

本 PR 落地了网关重构计划的第三步 [EPIC-GW-03]。 其核心目标是将本地 IPC 控制面的通信协议从前期的“裸 MessageFrame 直传”正式升级为 标准 JSON-RPC 2.0 协议。通过实现“外层 JSON-RPC 壳,内层 MessageFrame 语义”的归一化架构,我们彻底硬化了错误模型和数据契约,大幅降低了未来接入大模型 Runtime 和外部前端的改造成本。

💡 架构决策提示: 本期采用了直接切换 (Hard Cutover) 策略,不保留对旧版 MessageFrame 字节流的双栈兼容。因 gatewayurl-dispatch 均打包在同一单体二进制内同频升级,此举有效避免了技术债务的产生。

✨ 主要变更 (Key Changes)

1. JSON-RPC 协议归一化 (internal/gateway/protocol)

  • 新增完整的 JSON-RPC 2.0 类型定义 (JSONRPCRequest, JSONRPCResponse, JSONRPCError)。
  • 引入 延迟解析 (Deferred Parsing) 技巧:将 params 定义为 json.RawMessage,在确定 Method 后再精准反序列化(如 WakeIntent),提升了路由灵活性。
  • result 字段直接封装完整的 MessageFrame 对象,最大程度复用现有 Handler 逻辑。

2. 网关服务与错误模型硬化 (internal/gateway/server.go)

  • 网关解析链路已全面切换:JSON-RPC 字节流 -> NormalizeRPCRequest -> 内部 MessageFrame 分发。
  • 混合错误模型:全面对齐 JSON-RPC 标准。底层协议错误使用官方负数码(如 -32700, -32601),而业务层错误标识则被安全地放置在 error.data.gateway_code 中(如 invalid_action, missing_required_field)。

3. URL 派发器升级与健壮性修复 (internal/gateway/adapters/urlscheme)

  • url-dispatch 发送方同步切换为 JSON-RPC 封包。
  • 关联校验:增加了严密的响应一致性校验,拒绝 idaction 错配的幽灵响应。
  • I/O 阻塞修复:完善了基于 Context 取消的强行网络中断机制,修复了原先可能导致无限阻塞的潜在风险。

4. 安全漏洞修复 (internal/gateway/handlers)

  • 修复了在 Windows 等特定平台下,URL 唤醒参数针对 /... 等特殊绝对路径的越界识别边界问题。

✅ 验收标准 (Acceptance Criteria)

  • gateway.pingwake.openUrl 等底层链路全面通过 JSON-RPC 2.0 归一化层。
  • 成功与失败的 JSON-RPC 响应体均符合最新契约 (error.code + gateway_code)。
  • Context 取消与限流超时功能在新的 JSON-RPC 协议下均正常生效。

Closes #300

实现控制面底层 IPC 传输从“裸 MessageFrame”向“标准 JSON-RPC 2.0”的直接无缝切换,硬化内部契约,为后续 Runtime 接入奠定稳定基座。

主要改动:
1. 协议归一化:新增 JSON-RPC 解析层,使用 json.RawMessage 延迟解析 params,并统一收敛至内部 MessageFrame 进行路由。
2. 错误模型重构:采用标准 JSON-RPC 错误码 (error.code),并将网关业务错误码统一映射至 error.data.gateway_code。
3. 适配器升级:url-dispatch 全面切换为 JSON-RPC 收发,并补齐了严密的 RequestID/Action 响应关联校验。
4. 稳定性增强:修复 URL 调度器的 context 取消中断逻辑(防止无界阻塞),并修复 Windows 环境下的绝对路径越界检测漏洞。
5. 测试覆盖:大幅增补 Server/Dispatcher 协议回归单测,网关核心覆盖率达 95.3%。
@pionxe

pionxe commented Apr 15, 2026

Copy link
Copy Markdown
Collaborator Author

/review

@codecov

codecov Bot commented Apr 15, 2026

Copy link
Copy Markdown

fennoai[bot]

This comment was marked as outdated.

fennoai[bot]

This comment was marked as outdated.

@pionxe

pionxe commented Apr 15, 2026

Copy link
Copy Markdown
Collaborator Author

/review

fennoai[bot]

This comment was marked as outdated.

@pionxe

pionxe commented Apr 15, 2026

Copy link
Copy Markdown
Collaborator Author

/simplify

@fennoai

fennoai Bot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

处理结果

已按你的 /simplify 要求完成:

  1. 读取并评估历史 review 评论,确认 3 条都值得修复并已落地。
  2. 修复项:
  • internal/gateway/handlers/wake.go:补充与平台无关的 Windows 盘符前缀拦截(C:foo),避免 Linux 下 filepath.VolumeName 漏拦。
  • internal/gateway/protocol/jsonrpc.goJSONRPCResponse.ID 去掉 omitempty,确保未知请求 ID 的错误响应可序列化为 id: null(JSON-RPC 2.0 兼容)。
  • internal/gateway/adapters/urlscheme/dispatcher_test.go:成功路径补强 JSON-RPC 壳断言(jsonrpcidparams)。
  • 同步补测:
    • internal/gateway/protocol/jsonrpc_test.go 新增 id:null 编码断言。
    • internal/gateway/server_additional_test.go 新增 invalid JSON 场景 id == null 断言。
  1. 运行测试:
  • go test ./internal/gateway/... 通过
  • go test ./... 通过
  1. 按要求调用 code-simplifier 子代理复查,结果为 no-op(未发现可在不改行为前提下继续简化的点)。

  2. 已提交并推送到当前 PR 头分支:

  • commit: bd9cca6
  • pushed to: pionxe/neo-code:feat/gateway-epic-gw-03-jsonrpc-hardening

未执行项:无。

View job run

- block Windows drive-relative review paths across platforms
- ensure JSON-RPC error responses keep id field (null when unknown)
- strengthen dispatcher success-case RPC envelope assertions

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
@phantom5099

Copy link
Copy Markdown
Collaborator

/review

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed changed files across code quality, performance, security, and documentation accuracy. No actionable issues found.

@@ -0,0 +1,292 @@
package protocol

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed: no actionable issues identified in this PR.

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found one protocol-level regression worth fixing before relying on this JSON-RPC layer broadly.

Comment thread internal/gateway/protocol/jsonrpc.go Outdated
normalized := NormalizedRequest{}

requestID, idErr := normalizeJSONRPCID(request.ID)
normalized.ID = cloneJSONRawMessage(request.ID)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normalized.ID is copied from request.ID before normalizeJSONRPCID validation is checked. For invalid IDs (object/array/boolean/null), NormalizeJSONRPCRequest returns an error but still preserves the invalid ID, and dispatchRPCRequest then echoes that value in error.id. Per JSON-RPC 2.0, invalid request / invalid ID cases should return id: null when the request ID cannot be used. Suggest setting normalized.ID = nil when idErr != nil (or only assigning cloned ID after validation succeeds).

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Focused review on the JSON-RPC migration. I found 2 protocol-level issues worth fixing.

Comment thread internal/gateway/protocol/jsonrpc.go Outdated
normalized := NormalizedRequest{}

requestID, idErr := normalizeJSONRPCID(request.ID)
normalized.ID = cloneJSONRawMessage(request.ID)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normalized.ID is copied from the raw request before id validation. When id is present but invalid (e.g. object/array/bool), dispatchRPCRequest will echo that invalid id in the error response. In JSON-RPC 2.0, invalid/missing request ids should be returned as id: null for request-level errors. Consider only assigning normalized.ID after successful normalizeJSONRPCID, or forcing it to nil on idErr.

Comment thread internal/gateway/server.go Outdated
_ = s.writeRPCResponse(conn, encoder, protocol.NewJSONRPCErrorResponse(
nil,
protocol.NewJSONRPCError(
protocol.JSONRPCCodeInvalidParams,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oversized frame is classified as -32602 (Invalid params), but this failure happens before method/params parsing and is a request framing/protocol error. -32600 (Invalid Request) is a better fit (or a consistent parse-error policy). Current mapping can mislead clients and weakens error semantics for transport-level failures.

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completed review across changed files (code quality, performance, security, and documentation/test alignment).

No noteworthy issues found.


response := s.dispatchFrame(ctx, frame, runtimePort)
if !s.writeFrame(conn, encoder, response) {
rpcResponse := s.dispatchRPCRequest(ctx, rpcRequest, runtimePort)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed: no issues identified in this change set.

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consolidated review (deduplicated): 1 actionable issue found in JSON-RPC error correlation semantics.

Comment thread internal/gateway/protocol/jsonrpc.go Outdated
normalized := NormalizedRequest{}

requestID, idErr := normalizeJSONRPCID(request.ID)
normalized.ID = cloneJSONRawMessage(request.ID)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When id validation fails, normalized.ID currently echoes the original invalid id into the error response. For JSON-RPC invalid request/id cases, the response id should be null to avoid correlating with an invalid identifier. Consider setting normalized.ID = nil when normalizeJSONRPCID returns an error.

@pionxe

pionxe commented Apr 15, 2026

Copy link
Copy Markdown
Collaborator Author

/simplify

@fennoai

fennoai Bot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

已完成 /simplify 请求,并按“先看未解决 review,再修复,再简化”的顺序执行。

处理结果

  1. 读取历史评论并去重后,判定有 2 条值得修复的未解决项:
  • 非法 id 被错误回显到 JSON-RPC 错误响应。
  • 超长帧错误码语义使用 -32602 不准确。
  1. 已落实修复:
  • internal/gateway/protocol/jsonrpc.go
    • 调整 NormalizeJSONRPCRequest:仅在 id 校验成功后才赋值 normalized.ID,保证非法 id 场景最终编码为 id: null
    • 子代理简化(行为不变):清理 normalizeJSONRPCIDfloat64 分支无效变量使用,并简化分支局部变量写法。
  • internal/gateway/server.go
    • 超长帧错误从 JSONRPCCodeInvalidParams (-32602) 调整为 JSONRPCCodeInvalidRequest (-32600)
  1. 已补/调测试:
  • internal/gateway/protocol/jsonrpc_test.go
    • 新增非法 id 归一化时 normalized.ID == nil 覆盖。
  • internal/gateway/server_additional_test.go
    • 新增 dispatchRPCRequest 非法 id 响应序列化后 id: null 覆盖。
  • internal/gateway/server_test.go
    • 更新超长帧错误码断言为 -32600
  1. 验证:
  • go test ./internal/gateway/... 通过
  • go test ./... 通过
  1. 提交与推送:
  • commit: 7a093a6
  • pushed to: pionxe/neo-code:feat/gateway-epic-gw-03-jsonrpc-hardening

未完成项:无。

View job run

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
@phantom5099 phantom5099 merged commit 696e72f into 1024XEngineer:main Apr 15, 2026
2 checks passed
@fennoai fennoai Bot mentioned this pull request Apr 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[EPIC-GW-03] 本地控制面契约硬化(JSON-RPC 错误模型 + MessageFrame 归一化)

3 participants